#ifndef _JERASURE_H
#define _JERASURE_H

#include <stdint.h>
#include <vector>
#include <string>
#include <set>
#include "galois.h"
using namespace std;

typedef vector <unsigned int> IVec;
typedef vector <unsigned char> CVec;

class JER_Matrix {
	public:
		vector <IVec> Elts;
		int W;
		// Checked in test 10
		JER_Matrix( JER_Matrix &jm );
		// Checked in test 11
		void CreateIdentity();
		// Checked in test 16
		int Invertible();
		// Checked in test 15
		int Inverse();

		// (Checked within reed_sol generation methods)
		/* Changed for new Galois */
		JER_Matrix(int r, int c, int word_size);

		/* Added with new Galois implementation */
		Galois *gc;
		JER_Matrix(int r, int c, int word_size, int gi);
		
		// Checked throughout
		void Print();
		string String();
};

class JER_Slices {
	public:
		int K;
		int M;
		int W;
		int PS;
		int size;
		vector <unsigned char *> ptrs;
		vector <int> failures; // This is a maybe. However, it might be very clean to have this, and when
		// you first start up, you set failures = k, k+1, ..., k+m-1, and then “decode” to encode the
		// system.
};

class JER_Bitmatrix {
	public:
		vector <CVec> Elts;
		int W;
		int SUPERC;
		// (Checked within liberation generation methods)
		void Set(int r, int c, int val);
		// (Checked within liberation generation methods)
		int Isset(int r, int c);
		// (Checked within liberation generation methods)
		JER_Bitmatrix(int superr, int superc);
		// (Checked within liberation generation methods)
		JER_Bitmatrix(int superr, int superc, int w);
		// Checked in test 7
		JER_Bitmatrix(JER_Matrix &jm);
		//Checked in test 4
		JER_Bitmatrix(JER_Bitmatrix &jbm);
		/* In case we don't care about w */
		// Checked in test 18
		int Invertible();
		// Checked in test 5
		void CreateIdentity();
		// Checked in test 17
		int Inverse();
	
		// Checked throughout
		void Print();
		string String();
};

class JER_Schedule {
	public:
		vector <IVec> Elts;
};
// Checked in test 20
void JER_Matrix_Encode(JER_Slices *slices, JER_Matrix *jm);
// Checked in test 19
void JER_Bitmatrix_Encode(JER_Slices *slices, JER_Bitmatrix *jbm);
void JER_Schedule_Encode(JER_Slices *slices, JER_Schedule *sched);
int JER_Matrix_Decode(JER_Slices *slices, JER_Matrix *jm, int row_k_ones,
		vector <int> &erasures);
int JER_Bitmatrix_Decode(JER_Slices *slices, JER_Bitmatrix *jm, int row_k_ones,
		vector <int> &erasures);
int JER_Schedule_Decode_Lazy(JER_Slices *slices, JER_Bitmatrix *jm, vector <int> &erasures, int smart);
void JER_Free_Schedule_Cache(vector <JER_Schedule *> *cache);
int JER_Schedule_Decode_Cache(JER_Slices *slice, vector <JER_Schedule *> &cache, vector <int> &erasures);
// Checked in test 22
int JER_Make_Decoding_Matrix(JER_Matrix *jm, vector <int> &erased,
		JER_Matrix *decoding_jm, int *dm_ids);
// Checked in test 21
int JER_Make_Decoding_Bitmatrix(JER_Bitmatrix *jbm, vector <int> &erased, 
		JER_Bitmatrix *decoding_jm, int *dm_ids);
vector <int> JER_Erasures_To_Erased(int k, int m, vector <int> &erasures);
JER_Schedule *JER_BM_to_Schedule_Dumb(JER_Bitmatrix *jbm);
JER_Schedule *JER_BM_to_Schedule_CSHR(JER_Bitmatrix *jbm);
vector <JER_Schedule *> * JER_RAID_6_Schedule_Cache(JER_Bitmatrix *jbm, int technique);
/*???*/void JER_Do_Parity(JER_Slices *slices, unsigned char *parity_ptr);
//TODO
void JER_Matrix_Dotprod(JER_Slices *slice, JER_Matrix *jm, int row, 
		int *src_ids, int dest_id);
//TODO
void JER_Bitmatrix_Dotprod(JER_Slices *slice, JER_Bitmatrix *jbm, int row, 
		int *src_ids, int dest_id);
void JER_Do_Scheduled_Operations(unsigned char **ptrs, JER_Schedule *sched,int packetsize);
JER_Matrix JER_Matrix_Multiply(JER_Matrix *m1, JER_Matrix *m2);
void JER_Get_Stats(vector <double> &fill_in);
#endif
